/**
 * 图片处理服务
 * @module services/image
 */

const fs = require('fs');
const path = require('path');
const sharp = require('sharp');
const crypto = require('crypto');
const config = require('../config/config');

/**
 * 生成唯一文件名
 * @param {string} originalName - 原始文件名
 * @param {string} prefix - 文件名前缀
 * @returns {string} 生成的唯一文件名
 */
const generateUniqueFilename = (originalName, prefix = '') => {
  const timestamp = Date.now();
  const hash = crypto.randomBytes(8).toString('hex');
  const ext = path.extname(originalName);
  return `${prefix}_${timestamp}_${hash}${ext}`;
};

/**
 * 确保上传目录存在
 */
const ensureUploadDirExists = () => {
  if (!fs.existsSync(config.uploadDir)) {
    fs.mkdirSync(config.uploadDir, { recursive: true });
  }
};

/**
 * 压缩图片
 * @param {Object} file - 上传的文件对象
 * @param {Object} options - 压缩选项
 * @param {number} options.quality - 压缩质量 (1-100)
 * @param {boolean} options.resize - 是否调整大小
 * @param {number} options.maxWidth - 最大宽度
 * @param {number} options.maxHeight - 最大高度
 * @param {string} options.format - 输出格式 (original, jpg, png, webp)
 * @returns {Promise<Object>} 压缩结果
 */
exports.compressImage = async (file, options) => {
  ensureUploadDirExists();
  
  const { 
    quality = 75, 
    resize = false, 
    maxWidth = 1920, 
    maxHeight = 1080, 
    format = 'original' 
  } = options;
  
  // 获取原始文件信息
  const originalPath = file.path;
  const originalSize = fs.statSync(originalPath).size;
  
  // 读取图片元数据
  const metadata = await sharp(originalPath).metadata();
  
  // 确定输出格式
  let outputFormat = format;
  if (format === 'original') {
    outputFormat = metadata.format;
  }
  
  // 生成输出文件名
  const uniqueFilename = generateUniqueFilename(file.originalname, 'compressed');
  const outputPath = path.join(config.uploadDir, uniqueFilename);
  
  // 创建Sharp实例
  let sharpInstance = sharp(originalPath);
  
  // 如果需要调整大小
  if (resize && (metadata.width > maxWidth || metadata.height > maxHeight)) {
    sharpInstance = sharpInstance.resize({
      width: Math.min(metadata.width, maxWidth),
      height: Math.min(metadata.height, maxHeight),
      fit: 'inside',
      withoutEnlargement: true
    });
  }
  
  // 根据格式设置输出选项
  const formatOptions = {};
  
  if (outputFormat === 'jpeg' || outputFormat === 'jpg') {
    formatOptions.quality = quality;
    sharpInstance = sharpInstance.jpeg(formatOptions);
  } else if (outputFormat === 'png') {
    formatOptions.quality = quality;
    sharpInstance = sharpInstance.png(formatOptions);
  } else if (outputFormat === 'webp') {
    formatOptions.quality = quality;
    sharpInstance = sharpInstance.webp(formatOptions);
  }
  
  // 输出到文件
  await sharpInstance.toFile(outputPath);
  
  // 读取处理后的文件信息
  const compressedSize = fs.statSync(outputPath).size;
  const compressedMetadata = await sharp(outputPath).metadata();
  
  // 计算压缩比例
  const compressionRatio = Math.round((1 - compressedSize / originalSize) * 100);
  
  // 生成下载URL
  const downloadUrl = `/uploads/${uniqueFilename}`;
  
  // 设置过期时间（7天后）
  const now = new Date();
  const expiryTime = new Date(now.setDate(now.getDate() + 7)).toISOString();
  
  return {
    originalSize,
    compressedSize,
    compressionRatio,
    originalFormat: metadata.format,
    outputFormat,
    width: compressedMetadata.width,
    height: compressedMetadata.height,
    downloadUrl,
    expiryTime
  };
};

/**
 * 转换图片格式
 * @param {Object} file - 上传的文件对象
 * @param {Object} options - 转换选项
 * @param {string} options.format - 目标格式 (jpg, png, webp, gif)
 * @param {number} options.quality - 质量 (1-100)，仅适用于jpg和webp
 * @returns {Promise<Object>} 转换结果
 */
exports.convertImage = async (file, options) => {
  ensureUploadDirExists();
  
  const { format, quality = 90 } = options;
  
  // 获取原始文件信息
  const originalPath = file.path;
  const originalSize = fs.statSync(originalPath).size;
  
  // 读取图片元数据
  const metadata = await sharp(originalPath).metadata();
  
  // 生成输出文件名
  const uniqueFilename = generateUniqueFilename(
    path.basename(file.originalname, path.extname(file.originalname)) + '.' + format,
    'converted'
  );
  const outputPath = path.join(config.uploadDir, uniqueFilename);
  
  // 创建Sharp实例
  let sharpInstance = sharp(originalPath);
  
  // 根据格式设置输出选项
  const formatOptions = {};
  
  if (format === 'jpeg' || format === 'jpg') {
    formatOptions.quality = quality;
    await sharpInstance.jpeg(formatOptions).toFile(outputPath);
  } else if (format === 'png') {
    await sharpInstance.png().toFile(outputPath);
  } else if (format === 'webp') {
    formatOptions.quality = quality;
    await sharpInstance.webp(formatOptions).toFile(outputPath);
  } else if (format === 'gif') {
    await sharpInstance.gif().toFile(outputPath);
  } else {
    throw new Error(`不支持的格式: ${format}`);
  }
  
  // 读取转换后的文件信息
  const convertedSize = fs.statSync(outputPath).size;
  const convertedMetadata = await sharp(outputPath).metadata();
  
  // 生成下载URL
  const downloadUrl = `/uploads/${uniqueFilename}`;
  
  // 设置过期时间（7天后）
  const now = new Date();
  const expiryTime = new Date(now.setDate(now.getDate() + 7)).toISOString();
  
  return {
    originalSize,
    convertedSize,
    originalFormat: metadata.format,
    convertedFormat: format,
    width: convertedMetadata.width,
    height: convertedMetadata.height,
    downloadUrl,
    expiryTime
  };
};

/**
 * 裁剪图片
 * @param {Object} file - 上传的文件对象
 * @param {Object} options - 裁剪选项
 * @param {number} options.x - 裁剪起始x坐标
 * @param {number} options.y - 裁剪起始y坐标
 * @param {number} options.width - 裁剪宽度
 * @param {number} options.height - 裁剪高度
 * @param {string} options.format - 输出格式 (original, jpg, png, webp)
 * @returns {Promise<Object>} 裁剪结果
 */
exports.cropImage = async (file, options) => {
  ensureUploadDirExists();
  
  const { x, y, width, height, format = 'original' } = options;
  
  // 获取原始文件信息
  const originalPath = file.path;
  const originalSize = fs.statSync(originalPath).size;
  
  // 读取图片元数据
  const metadata = await sharp(originalPath).metadata();
  
  // 确定输出格式
  let outputFormat = format;
  if (format === 'original') {
    outputFormat = metadata.format;
  }
  
  // 生成输出文件名
  const uniqueFilename = generateUniqueFilename(file.originalname, 'cropped');
  const outputPath = path.join(config.uploadDir, uniqueFilename);
  
  // 创建Sharp实例并裁剪
  let sharpInstance = sharp(originalPath).extract({
    left: parseInt(x, 10),
    top: parseInt(y, 10),
    width: parseInt(width, 10),
    height: parseInt(height, 10)
  });
  
  // 根据格式设置输出
  if (outputFormat === 'jpeg' || outputFormat === 'jpg') {
    sharpInstance = sharpInstance.jpeg();
  } else if (outputFormat === 'png') {
    sharpInstance = sharpInstance.png();
  } else if (outputFormat === 'webp') {
    sharpInstance = sharpInstance.webp();
  }
  
  // 输出到文件
  await sharpInstance.toFile(outputPath);
  
  // 读取裁剪后的文件信息
  const croppedSize = fs.statSync(outputPath).size;
  const croppedMetadata = await sharp(outputPath).metadata();
  
  // 生成下载URL
  const downloadUrl = `/uploads/${uniqueFilename}`;
  
  // 设置过期时间（7天后）
  const now = new Date();
  const expiryTime = new Date(now.setDate(now.getDate() + 7)).toISOString();
  
  return {
    originalSize,
    croppedSize,
    originalDimensions: {
      width: metadata.width,
      height: metadata.height
    },
    croppedDimensions: {
      width: croppedMetadata.width,
      height: croppedMetadata.height
    },
    downloadUrl,
    expiryTime
  };
};

/**
 * 旋转和翻转图片
 * @param {Object} file - 上传的文件对象
 * @param {Object} options - 旋转选项
 * @param {number} options.rotation - 旋转角度 (0, 90, 180, 270)
 * @param {boolean} options.flipHorizontal - 是否水平翻转
 * @param {boolean} options.flipVertical - 是否垂直翻转
 * @param {string} options.format - 输出格式 (original, jpg, png, webp)
 * @returns {Promise<Object>} 旋转结果
 */
exports.rotateImage = async (file, options) => {
  ensureUploadDirExists();
  
  const { 
    rotation = 0, 
    flipHorizontal = false, 
    flipVertical = false, 
    format = 'original' 
  } = options;
  
  // 获取原始文件信息
  const originalPath = file.path;
  const originalSize = fs.statSync(originalPath).size;
  
  // 读取图片元数据
  const metadata = await sharp(originalPath).metadata();
  
  // 确定输出格式
  let outputFormat = format;
  if (format === 'original') {
    outputFormat = metadata.format;
  }
  
  // 生成输出文件名
  const uniqueFilename = generateUniqueFilename(file.originalname, 'rotated');
  const outputPath = path.join(config.uploadDir, uniqueFilename);
  
  // 创建Sharp实例
  let sharpInstance = sharp(originalPath);
  
  // 旋转图片
  if (rotation) {
    sharpInstance = sharpInstance.rotate(parseInt(rotation, 10));
  }
  
  // 翻转图片
  if (flipHorizontal || flipVertical) {
    sharpInstance = sharpInstance.flip(flipVertical).flop(flipHorizontal);
  }
  
  // 根据格式设置输出
  if (outputFormat === 'jpeg' || outputFormat === 'jpg') {
    sharpInstance = sharpInstance.jpeg();
  } else if (outputFormat === 'png') {
    sharpInstance = sharpInstance.png();
  } else if (outputFormat === 'webp') {
    sharpInstance = sharpInstance.webp();
  }
  
  // 输出到文件
  await sharpInstance.toFile(outputPath);
  
  // 读取处理后的文件信息
  const processedSize = fs.statSync(outputPath).size;
  
  // 生成下载URL
  const downloadUrl = `/uploads/${uniqueFilename}`;
  
  // 设置过期时间（7天后）
  const now = new Date();
  const expiryTime = new Date(now.setDate(now.getDate() + 7)).toISOString();
  
  return {
    originalSize,
    processedSize,
    rotation,
    flipHorizontal,
    flipVertical,
    downloadUrl,
    expiryTime
  };
};

/**
 * 添加水印
 * @param {Object} file - 上传的文件对象
 * @param {Object} options - 水印选项
 * @param {string} options.watermarkType - 水印类型 (text, image)
 * @param {string} options.watermarkText - 水印文本
 * @param {Object} options.watermarkImage - 水印图片文件
 * @param {string} options.position - 水印位置 (center, topLeft, topRight, bottomLeft, bottomRight)
 * @param {number} options.opacity - 水印透明度 (0.1-1.0)
 * @param {number} options.size - 水印大小，相对于原图的比例 (0.1-1.0)
 * @param {string} options.format - 输出格式 (original, jpg, png, webp)
 * @returns {Promise<Object>} 水印添加结果
 */
exports.addWatermark = async (file, options) => {
  ensureUploadDirExists();
  
  const { 
    watermarkType, 
    watermarkText, 
    watermarkImage, 
    position = 'bottomRight', 
    opacity = 0.5,
    size = 0.2,
    format = 'original'
  } = options;
  
  // 获取原始文件信息
  const originalPath = file.path;
  const originalSize = fs.statSync(originalPath).size;
  
  // 读取图片元数据
  const metadata = await sharp(originalPath).metadata();
  
  // 确定输出格式
  let outputFormat = format;
  if (format === 'original') {
    outputFormat = metadata.format;
  }
  
  // 生成输出文件名
  const uniqueFilename = generateUniqueFilename(file.originalname, 'watermarked');
  const outputPath = path.join(config.uploadDir, uniqueFilename);
  
  // 计算水印位置
  const getPosition = (position, width, height, watermarkWidth, watermarkHeight) => {
    const padding = 20; // 内边距
    
    switch (position) {
      case 'topLeft':
        return { left: padding, top: padding };
      case 'topRight':
        return { left: width - watermarkWidth - padding, top: padding };
      case 'bottomLeft':
        return { left: padding, top: height - watermarkHeight - padding };
      case 'bottomRight':
        return { left: width - watermarkWidth - padding, top: height - watermarkHeight - padding };
      case 'center':
      default:
        return { left: Math.floor((width - watermarkWidth) / 2), top: Math.floor((height - watermarkHeight) / 2) };
    }
  };
  
  // 创建Sharp实例
  let sharpInstance = sharp(originalPath);
  
  // 根据水印类型添加水印
  if (watermarkType === 'text' && watermarkText) {
    // 创建文字水印
    const textSvg = Buffer.from(`
      <svg width="${metadata.width}" height="${metadata.height}">
        <style>
          .title { fill: rgba(255, 255, 255, ${opacity}); font-size: ${Math.floor(metadata.height * size / 10)}px; font-weight: bold; font-family: "Arial", sans-serif; }
        </style>
        <text x="50%" y="50%" text-anchor="middle" class="title">${watermarkText}</text>
      </svg>
    `);
    
    // 添加水印
    sharpInstance = sharpInstance.composite([{
      input: textSvg,
      blend: 'over'
    }]);
  } else if (watermarkType === 'image' && watermarkImage) {
    // 处理图片水印
    const watermarkSharp = sharp(watermarkImage.path);
    const watermarkMetadata = await watermarkSharp.metadata();
    
    // 调整水印大小
    const watermarkWidth = Math.floor(metadata.width * size);
    const watermarkResized = await watermarkSharp
      .resize({ width: watermarkWidth })
      .ensureAlpha(opacity)
      .toBuffer();
    
    // 重新获取调整后的水印尺寸
    const resizedWatermarkMetadata = await sharp(watermarkResized).metadata();
    
    // 计算位置
    const watermarkPosition = getPosition(
      position, 
      metadata.width, 
      metadata.height, 
      resizedWatermarkMetadata.width, 
      resizedWatermarkMetadata.height
    );
    
    // 添加水印
    sharpInstance = sharpInstance.composite([{
      input: watermarkResized,
      blend: 'over',
      ...watermarkPosition
    }]);
  }
  
  // 根据格式设置输出
  if (outputFormat === 'jpeg' || outputFormat === 'jpg') {
    sharpInstance = sharpInstance.jpeg();
  } else if (outputFormat === 'png') {
    sharpInstance = sharpInstance.png();
  } else if (outputFormat === 'webp') {
    sharpInstance = sharpInstance.webp();
  }
  
  // 输出到文件
  await sharpInstance.toFile(outputPath);
  
  // 读取处理后的文件信息
  const processedSize = fs.statSync(outputPath).size;
  
  // 生成下载URL
  const downloadUrl = `/uploads/${uniqueFilename}`;
  
  // 设置过期时间（7天后）
  const now = new Date();
  const expiryTime = new Date(now.setDate(now.getDate() + 7)).toISOString();
  
  return {
    originalSize,
    processedSize,
    watermarkType,
    position,
    downloadUrl,
    expiryTime
  };
}; 